`timescale 1ns/1ps
//in wrapper ,all control signals active high
//16384*128 = 4*4096*128 = 4*4096*32*4
module ram_dp_d16384_w128_wrapper (clka,clkb,wea,web,addra,addrb,dina,dinb,douta,doutb,ram_dp_cfg_register);
  input  clka;
  input  clkb;
  input [11:0] ram_dp_cfg_register;
  input  wea; //write enable,active high
  input  web; 
  input [13:0] addra;
  input [13:0] addrb;
  input [127:0] dina;
  input [127:0] dinb;
  output reg [127:0] douta;//rdata
  output reg [127:0] doutb;

reg [3:0] cena,cenb;

//14'h0000 ~ 14'h0FFF   0  [13:12]=2'b00
//14'h1000 ~ 14'h1FFF   1  [13:12]=2'b01
//14'h2000 ~ 14'h2FFF   2  [13:12]=2'b10
//14'h3000 ~ 14'h3FFF   3  [13:12]=2'b11

wire [3 : 0] wea_array;
wire [3 : 0] web_array;


wire [3 : 0] cena_array;
wire [3 : 0] cenb_array;

reg  [3 : 0] cena_array_ff;
reg  [3 : 0] cenb_array_ff;

wire [511:0] douta_total;
wire [511:0] doutb_total;

	assign cena_array = cena;
	assign cenb_array = cenb;

	always @(posedge clka) begin
		cena_array_ff <= cena_array;
	end

	always @(posedge clkb) begin
		cenb_array_ff <= cenb_array;
	end

	always @(*) begin
		case (cena_array_ff)
			4'b0001: douta = douta_total[127:0];
			4'b0010: douta = douta_total[255:128];
			4'b0100: douta = douta_total[383:256];
			4'b1000: douta = douta_total[511:384];
			default: douta = 128'b0;
		endcase
	end

	always @(*) begin
		case (cenb_array_ff)
			4'b0001: doutb = doutb_total[127:0];
			4'b0010: doutb = doutb_total[255:128];
			4'b0100: doutb = doutb_total[383:256];
			4'b1000: doutb = doutb_total[511:384];
			default: doutb = 128'b0;
		endcase
	end

wire [3:0] sela,selb;
genvar i,j;
generate
	//16384*128=4*4096*128
	for(i = 0;i <= 3;i = i + 1)
	begin: ram_gen_01
	
  //write first
  always@(*)begin
    if((addra == addrb)) begin
      case({wea,web}) 
	    2'b00:begin//(rd a&b) 
		    cena[i] = sela[i];
	        cenb[i] = selb[i];
        end
        2'b01:begin//(read a,write b) ,write b first
		    cena[i] = 1'b0;
	        cenb[i] = selb[i];
        end
        2'b10:begin//(write a,read b) ,write a first
		    cena[i] = sela[i];
	        cenb[i] = 1'b0;
        end
        2'b11:begin//(write a&b) ,write a first
		    cena[i] = sela[i];
	        cenb[i] = 1'b0;
        end
	      default:begin
		    cena[i] = sela[i];
	        cenb[i] = selb[i];
        end
      endcase
    end
    else begin
         cena[i] = sela[i];//1'b0;
	     cenb[i] = selb[i];//1'b0;
    end
  end

		assign sela[i] = (addra[13 : 12] == i);//1
		assign selb[i] = (addrb[13 : 12] == i);//1
		
		assign wea_array[i] = cena[i] & wea;//1 = 1 ? 1
		assign web_array[i] = cenb[i] & web;//1 = 1 ? 1

		//4096*128=4096*32*4
		for (j = 1;j <= 4;j = j + 1) begin: ram_gen_01
			ram_dp_d4096_w32 U_ram_dp_d4096_w32(
				.CENYA(),  
				.WENYA(),
				.AYA(),
				.CENYB(),
				.WENYB(),
				.AYB(),
				.QA(douta_total[(128*i)+32*j-1:(128*i)+(32*(j-1))]),
				.QB(doutb_total[(128*i)+32*j-1:(128*i)+(32*(j-1))]),
				.SOA(),
				.SOB(),
				.CLKA(clka),
				.CENA(~cena[i]),
				.WENA(~wea_array[i]),
				.AA(addra[11:0]),
				.DA(dina[32*j-1:32*(j-1)]),
				.CLKB(clkb),
				.CENB(~cenb[i]),
				.WENB(1'b1),//(~web),
				//.WENB(~web),
				.AB(addrb[11:0]),
				.DB(dinb[32*j-1:32*(j-1)]),
				.EMAA(ram_dp_cfg_register[11:9]),
				.EMAWA(ram_dp_cfg_register[8:7]),
				.EMASA(ram_dp_cfg_register[6]),
				.EMAB(ram_dp_cfg_register[5:3]),
				.EMAWB(ram_dp_cfg_register[2:1]),
				.EMASB(ram_dp_cfg_register[0]),
				.TENA(1'b1),
				.TCENA(1'b1),
				.TWENA(1'b1),
				.TAA(12'b0),
				.TDA(32'b0),
				.TENB(1'b1),
				.TCENB(1'b1),
				.TWENB(1'b1),
				.TAB(12'b0),
				.TDB(32'b0),
				.RET1N(1'b1),
				.SIA(2'b1),
				.SEA(1'b0),
				.DFTRAMBYP(1'b0),
				.SIB(2'b1),
				.SEB(1'b0),
				.COLLDISN(1'b1) 
			);
		end
	end
endgenerate

endmodule
